import 'package:flutter/material.dart';

///
/// 包含以下方法：
/// - [builder]: 接收ScrollController和_itemKeys的builder函数。
/// - [onExposure]: 曝光回调。
/// - [onDisappear]: 消失回调。
///
///

//第一版：
// class ScrollviewExposureTracker extends StatefulWidget {
//   final Widget Function(ScrollController, Map<int, GlobalKey>) builder;
//   final Function(int) onExposure; // 曝光回调
//   final Function(int)? onDisappear; // 消失回调

//   const ScrollviewExposureTracker({
//     Key? key,
//     required this.builder,
//     required this.onExposure,
//     this.onDisappear,
//   }) : super(key: key);

//   @override
//   _ExposureTrackerWidgetState createState() => _ExposureTrackerWidgetState();
// }

// class _ExposureTrackerWidgetState extends State<ScrollviewExposureTracker> {
//   final ScrollController _scrollController = ScrollController();
//   final Map<int, GlobalKey> _itemKeys = {}; //记录创建过的item
//   final Map<int, bool> _exposureState = {}; // 记录每个item的曝光状态

//   @override
//   void initState() {
//     super.initState();
//     _scrollController.addListener(_checkExposureAndDisappear);
//   }

//   @override
//   void dispose() {
//     _scrollController.removeListener(_checkExposureAndDisappear);
//     _scrollController.dispose();
//     super.dispose();
//   }

//   void _checkExposureAndDisappear() {
//     final RenderBox? renderBox = context.findRenderObject() as RenderBox?;
//     if (renderBox == null) return;

//     final offset = _scrollController.offset;
//     final viewportHeight = renderBox.size.height;

//     //通过高度和偏移量计算是否在可见区域
//     _itemKeys.forEach((index, key) {
//       final RenderBox? itemRenderBox =
//           key.currentContext?.findRenderObject() as RenderBox?;
//       if (itemRenderBox != null) {
//         final itemOffset = itemRenderBox.localToGlobal(Offset.zero);
//         final itemHeight = itemRenderBox.size.height;
//         print(itemOffset.dx);
//         // 判断item是否在可见区域内
//         final isVisible = itemOffset.dy + itemHeight > offset &&
//             itemOffset.dy < offset + viewportHeight;

//         if (isVisible) {
//           // 如果item可见且未曝光过，则触发曝光回调
//           if (!_exposureState.containsKey(index)) {
//             _exposureState[index] = true;
//             widget.onExposure(index);
//           }
//         } else {
//           // 如果item不可见且曾经曝光过，则触发消失回调
//           if (_exposureState.containsKey(index)) {
//             _exposureState.remove(index);
//             widget.onDisappear?.call(index);
//           }
//         }
//       }
//     });
//   }

//   @override
//   Widget build(BuildContext context) {
//     return NotificationListener<ScrollNotification>(
//       onNotification: (notification) {
//         _checkExposureAndDisappear();
//         return true;
//       },
//       child: widget.builder(_scrollController, _itemKeys),
//     );
//   }
// }

//第二版：对循环做了节流技术 和 缓存计算结果
class ScrollviewExposureTracker extends StatefulWidget {
  final Widget Function(ScrollController, Map<int, GlobalKey>) builder;
  final Function(int) onExposure; // 曝光回调
  final Function(int)? onDisappear; // 消失回调

  const ScrollviewExposureTracker({
    Key? key,
    required this.builder,
    required this.onExposure,
    this.onDisappear,
  }) : super(key: key);

  @override
  _ExposureTrackerWidgetState createState() => _ExposureTrackerWidgetState();
}

class _ExposureTrackerWidgetState extends State<ScrollviewExposureTracker> {
  final ScrollController _scrollController = ScrollController();
  final Map<int, GlobalKey> _itemKeys = {}; // 记录创建过的item
  final Map<int, bool> _exposureState = {}; // 记录每个item的曝光状态
  bool _isComputing = false; // 防止重复计算
  final Map<int, double> _itemHeights = {}; // 缓存每个item的高度

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(_throttleCheckExposureAndDisappear);
  }

  @override
  void dispose() {
    _scrollController.removeListener(_throttleCheckExposureAndDisappear);
    _scrollController.dispose();
    super.dispose();
  }

  // 节流函数，减少滚动事件的触发频率
  void _throttleCheckExposureAndDisappear() {
    if (_isComputing) return;
    _isComputing = true;

    Future.delayed(const Duration(milliseconds: 100), () {
      _isComputing = false;
      _checkExposureAndDisappear();
    });
  }

  // 计算可见性
  void _checkExposureAndDisappear() {
    final RenderBox? renderBox = context.findRenderObject() as RenderBox?;
    if (renderBox == null) return;

    final offset = _scrollController.offset;
    final viewportHeight = renderBox.size.height;

    // 遍历所有item
    _itemKeys.forEach((index, key) {
      final RenderBox? itemRenderBox =
          key.currentContext?.findRenderObject() as RenderBox?;
      if (itemRenderBox != null) {
        final itemOffset = itemRenderBox.localToGlobal(Offset.zero);
        final itemHeight = _itemHeights[index] ?? itemRenderBox.size.height;

        // 缓存item的高度
        if (!_itemHeights.containsKey(index)) {
          _itemHeights[index] = itemHeight;
        }

        // 判断item是否在可见区域内
        final isVisible = itemOffset.dy + itemHeight > offset &&
            itemOffset.dy < offset + viewportHeight;

        if (isVisible) {
          // 如果item可见且未曝光过，则触发曝光回调
          if (!_exposureState.containsKey(index)) {
            _exposureState[index] = true;
            widget.onExposure(index);
          }
        } else {
          // 如果item不可见且曾经曝光过，则触发消失回调
          if (_exposureState.containsKey(index)) {
            _exposureState.remove(index);
            widget.onDisappear?.call(index);
          }
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return NotificationListener<ScrollNotification>(
      onNotification: (notification) {
        _throttleCheckExposureAndDisappear();
        return true;
      },
      child: widget.builder(_scrollController, _itemKeys),
    );
  }
}
